#include "SelectionComp.h"

#include <QtGui/QButtonGroup>
#include <QtGui/QGroupBox>
#include <QtGui/QGridLayout>
#include <QtGui/QVBoxLayout>
#include <QtGui/QHBoxLayout>
#include <QtGui/QCheckBox>
#include <QtGui/QPushButton>
#include <QtGui/QLCDNumber>

#include "Qlib.h"

using namespace std;

/**
 * Constructeur permettant de sélectionner plusieurs objets parmi une
 * liste.
 *
 * @param nbr nombre d'objets
 * @param noms pointeur sur le premier élément de la liste de noms
 * @param titre nom du groupe d'objets
 * @param cout pointeur sur le premier élément de la liste de coûts
 * @param pp nombre de pp que l'on peut dépenser
 * @param parent widget parent de l'objet, (par défaut, pas de parent)
 */
SelectionComp::SelectionComp(const unsigned int& nbr, const string* noms,
			     const string& titre, const unsigned int* cout,
			     const unsigned int& pp, QWidget *parent)
  : BaseSousSel( QString::fromUtf8("SelectionComp"), nbr, noms, titre,
		 parent ), PP( pp ), selectionGroupe( false )
{
  nbrPP = new QLCDNumber(this);
  nbrPP -> setSegmentStyle(QLCDNumber::Flat);

  nbrPP -> display( PP );

  for (unsigned int i(0); i < dimension; i++)
    Cout.push_back( *(cout + i) );

  fenetreLayout -> addWidget( nbrPP );
  fenetreLayout -> addWidget( boite );

  connect( groupe, SIGNAL( buttonClicked(int) ), this, SLOT( ajoutComp(int) ) );

  preparerBoutons();

  setFenetreLayout();
}

/**
 * Constructeur permettant de sélectionner plusieurs objets parmi une liste.
 *
 * @param nbr nombre d'objets
 * @param noms contient la liste de noms
 * @param titre nom du groupe d'objets
 * @param cout contient la liste de coûts
 * @param pp nombre de pp que l'on peut dépenser
 * @param parent widget parent de l'objet, (par défaut, pas de parent)
 */
SelectionComp::SelectionComp(const unsigned int& nbr,
			     const vector<string> noms, const string& titre,
			     const vector<unsigned int> cout,
			     const unsigned int& pp, QWidget *parent)
  : BaseSousSel( QString::fromUtf8("SelectionComp"), nbr, noms, titre,
		 parent ), PP( pp ), selectionGroupe( false )
{
  nbrPP = new QLCDNumber(this);
  nbrPP -> setSegmentStyle(QLCDNumber::Flat);

  nbrPP -> display( PP );

  Cout.assign( cout.begin(), cout.end() );

  fenetreLayout -> addWidget( nbrPP );
  fenetreLayout -> addWidget( boite );

  connect( groupe, SIGNAL( buttonClicked(int) ), this, SLOT( ajoutComp(int) ) );
  
  preparerBoutons();
  
  setFenetreLayout();
}

/**
 * Constructeur permettant de sélectionner plusieurs objets parmi une liste.
 *
 * @param nbr nombre d'objets
 * @param noms pointeur sur le premier élément de la liste de noms
 * @param deja conteneur des objets déjà connus
 * @param titre nom du groupe d'objets
 * @param cout pointeur sur le premier élément de la liste de coûts
 * @param pp nombre de pp que l'on peut dépenser
 * @param parent widget parent de l'objet, (par défaut, pas de parent)
 */
SelectionComp::SelectionComp(const unsigned int& nbr, const string* noms,
			     const vector<bool>& deja, const string& titre,
			     const unsigned int* cout, const unsigned int& pp,
			     QWidget *parent)
  : BaseSousSel( QString::fromUtf8("SelectionComp"), nbr, noms, deja,
		 titre, parent ), PP( pp ), selectionGroupe( false )
{
  nbrPP = new QLCDNumber(this);
  nbrPP -> setSegmentStyle(QLCDNumber::Flat);

  nbrPP -> display( PP );

  for (unsigned int i(0); i < dimension; i++)
    Cout.push_back( *(cout + i) );

  fenetreLayout -> addWidget( nbrPP );
  fenetreLayout -> addWidget( boite );

  connect( groupe, SIGNAL( buttonClicked(int) ), this, SLOT( ajoutComp(int) ) );

  preparerBoutons();

  setFenetreLayout();
}

/**
 * Constructeur permettant de sélectionner plusieurs objets parmi une liste.
 *
 * @param nbr nombre d'objets
 * @param noms contient la liste de noms
 * @param deja conteneur des objets déjà connus
 * @param titre nom du groupe d'objets
 * @param cout contient la liste de coûts
 * @param pp nombre de pp que l'on peut dépenser
 * @param parent widget parent de l'objet, (par défaut, pas de parent)
 */
SelectionComp::SelectionComp(const unsigned int& nbr, const vector<string> noms,
			     const vector<bool>& deja, const string& titre, 
			     const vector<unsigned int> cout,
			     const unsigned int& pp, QWidget *parent)
  : BaseSousSel( QString::fromUtf8("SelectionComp"), nbr, noms, deja, titre,
		 parent ), PP( pp ), selectionGroupe( false )
{
  nbrPP = new QLCDNumber(this);
  nbrPP -> setSegmentStyle(QLCDNumber::Flat);

  nbrPP -> display( PP );

  for (unsigned int i(0); i < dimension; i++)
    Cout.push_back( cout[i] );

  fenetreLayout -> addWidget( nbrPP );
  fenetreLayout -> addWidget( boite );

  connect( groupe, SIGNAL( buttonClicked(int) ), this, SLOT( ajoutComp(int) ) );

  preparerBoutons();

  setFenetreLayout();
}

/**
 * Constructeur de copie. Il faut s'occuper du coût des compétences,
 * le reste des listes étant géré par la classe mère.
 *
 * @param selComp instance de SelectionComp à dupliquer.
 */
SelectionComp::SelectionComp(const SelectionComp& selComp)
  : BaseSousSel( selComp ), PP( selComp.PP ),
    selectionGroupe( selComp.selectionGroupe )
{
  nbrPP = new QLCDNumber(this);
  nbrPP -> setSegmentStyle(QLCDNumber::Flat);

  nbrPP -> display( PP );

  Cout.assign( selComp.Cout.begin(), selComp.Cout.end() );
  
  fenetreLayout -> addWidget( nbrPP );
  fenetreLayout -> addWidget( boite );

  connect( groupe, SIGNAL( buttonClicked(int) ), this, SLOT( ajoutComp(int) ) );

  preparerBoutons();

  setFenetreLayout();
}

/**
 * Destructeur, ne fait rien de spécial
 */
SelectionComp::~SelectionComp()
{}

/**
 * Effectue la sélection et permet de récupérer le choix opéré.
 *
 * Le niveau de sortie est paramétré par BaseSousSel::interne :\n
 * - \e FUNC  affiche les messages de début et de fin de méthode.\n
 * - \e DEBUG affiche le nombre d'items, et un message lors de la
     sélection.
     *
 * @param vec liste des objets choisis, modifié par la méthode.
 * @return StatusCode \e true si sélection effectuée, \e false si
 * annulée, le nombre de pp restant est dans valeur().
 */
StatusCode SelectionComp::selectionFaite(vector<unsigned int>& vec)
{
  /*Debug::*/empileNiveau( &interne );
  func() << "SelectionComp::selectionFaite -> début" << endmsg;

  this -> exec();

  debug() << "dimension " << dimension << endmsg;

  if ( OK )
    {

      if ( selectionGroupe && groupe -> button( dimension - 1 ) -> isChecked() )
	{
	  debug() << "Groupe sélectionné" << endmsg;
	  for (unsigned int i(0); i < dimension - 1; i++)
	    vec.push_back(i);
	  
	  func() << "SelectionComp::selectionFaite -> fin" << endmsg;
	  /*Debug::*/depileNiveau();

	  return StatusCode( OK, PP );
	}
      
      for (unsigned int i(0); i < dimension; i++)
	{
	  if (groupe -> button(i) -> isChecked() &&
	      groupe -> button(i) -> isEnabled())
	    {
	      debug()  << "élément " << i << " sélectionné" << endmsg;
	      vec.push_back(i);
	    }
	}
    }

  func() << "SelectionComp::selectionFaite -> fin" << endmsg;
  /*Debug::*/depileNiveau();

  return StatusCode( OK, PP );
}

/**
 * Permet d'activer la sélection par groupe.
 *
 * @param selGrp \e true si oui, \e false sinon.
 */
void SelectionComp::setSelectionGroupe(const bool& selGrp)
{
  selectionGroupe = selGrp;
}

/**
 * Ajoute les boutons "OK" et "Annuler" dans le conteneur boutons. La
 * méthode existe pour éviter de dupliquer ces 6 lignes dans les
 * différents constructeurs.
 */
void SelectionComp::preparerBoutons()
{
  boutons.push_back( new QPushButton( trUtf8("&Annuler"), this ) );
  boutons.back() -> setToolTip( trUtf8("Revenir à la fenêtre principale sans sauver") );
  connect( boutons.back(), SIGNAL( clicked() ), this, SLOT( annuler() ) );

  boutons.push_back( new QPushButton( trUtf8("&OK"), this ) );
  boutons.back() -> setToolTip( trUtf8("Ajouter les compétences sélectionnées") );
  connect( boutons.back(), SIGNAL( clicked() ), this, SLOT( fermer() ) );
}

/**
 * Permet d'ajouter / retrancher un item à la sélection. Un ajout
 * n'est possible que si le nombre courant de PP est supérieur au coût
 * de l'item. Lors de la suppression d'un item, son coût est ajouté au
 * total de PP courant.
 *
 * Le niveau de sortie est paramétré par BaseSouSel::gestionListe :\n
 * - \e FUNC  affiche les messages de début et de fin de méthode.\n
 * - \e DEBUG affiche le nom de l'item ajouté / supprimé.
 *
 * @param i numéro de l'item à ajouter / supprimer.
 */
void SelectionComp::ajoutComp(const int& i)
{
  /*Debug::*/empileNiveau( &gestionListe );
  func() << "SelectionComp::ajoutComp -> début" << endmsg;

  if ( groupe -> button( i ) -> isChecked() )
    {
      if ( static_cast<int>(Cout[i]) > PP )
	{
	  groupe -> button(i) -> setChecked( false );
	}
      else
	{
	  debug() << "Ajout de "
		  << toUtf8StdString( groupe -> button(i) -> text() )
		  << endmsg;
	  PP -= Cout[i];
	  nbrPP -> display( PP );
	}
    }
  else
    {
      debug() << "Suppression de "
	      << toUtf8StdString( groupe -> button(i) -> text() )
	      << endmsg;
      PP += Cout[i];
      nbrPP -> display( PP );
    }

  func() << "SelectionComp::ajoutComp -> fin" << endmsg;
  /*Debug::*/depileNiveau();
}

/**
 * La méthode annuler() est redéfinie ici pour s'assurer qu'aucun item
 * n'est sélectionné lors d'une annulation. Sinon même en annulant la
 * sélection, le conteneur en retour de selectionFaite ne sera pas
 * vide. On supprime donc tous les choix effectués en utilisant la
 * méthode ajoutComp.
 */
void SelectionComp::annuler()
{
  OK = false;

  for (unsigned int i(0); i < dimension; i++)
    {
      if ( groupe -> button( i ) -> isChecked() &&
	   groupe -> button( i ) -> isEnabled()  )
	{
	  groupe -> button( i ) -> setChecked( false );
	  ajoutComp( i );
	}
    }

  close();
}
